home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / WASTE 1.1a4 / WASTE Source / WEInlineInput.p < prev    next >
Encoding:
Text File  |  1994-10-31  |  14.4 KB  |  547 lines  |  [TEXT/PJMM]

  1. unit WEInlineInput;
  2.  
  3. { WASTE PROJECT: }
  4. { Inline Input Support }
  5.  
  6. { Copyright © 1993-1994 Marco Piovanelli }
  7. { All Rights Reserved }
  8.  
  9. interface
  10.     uses
  11.         WEHighLevelEditing;
  12.  
  13.     function WEInstallTSMHandlers: OSErr;
  14.  
  15. implementation
  16.     uses
  17.         TextServices;
  18.  
  19. {$IFC WASTE_SEGMENT}
  20. {$S WASTE_TSM_SUPPORT}
  21. {$ENDC}
  22.  
  23.     procedure CallPreUpdate (hWE: WEHandle;
  24.                                     preUpdateProcPtr: ProcPtr);
  25.     inline
  26.         $205F,                    { movea.l (sp)+, a0 }
  27.         $4E90;                    { jsr (a0) }
  28.  
  29.     procedure CallPostUpdate (hWE: WEHandle;
  30.                                     fixLength: LongInt;
  31.                                     inputAreaStart, inputAreaEnd: LongInt;
  32.                                     pinRangeStart, pinRangeEnd: LongInt;
  33.                                     postUpdateProcPtr: ProcPtr);
  34.     inline
  35.         $205F,                    { movea.l (sp)+, a0 }
  36.         $4E90;                    { jsr (a0) }
  37.  
  38.     function _WEHiliteRangeArray (hTray: TextRangeArrayHandle;
  39.                                     hWE: WEHandle): OSErr;
  40.         label
  41.             1;
  42.         var
  43.             pWE: WEPtr;
  44.             pRange: TextRangePtr;
  45.             rangeStart, rangeEnd: LongInt;
  46.             hiliteStyle: Integer;
  47.             ts: WETextStyle;
  48.             rangeIndex: Integer;
  49.             saveTrayLock: Boolean;
  50.             err: OSErr;
  51.     begin
  52.         pWE := hWE^;
  53.  
  54. { lock down the range array }
  55.         saveTrayLock := _WESetHandleLock(hTray, true);
  56.         rangeIndex := hTray^^.fNumOfRanges - 1;
  57.         pRange := @hTray^^.fRange;
  58.  
  59. { walk the hilite range array }
  60.         while (rangeIndex >= 0) do
  61.             begin
  62.  
  63. { the offsets in the range array are relative to the beginning }
  64. { of the active input area: convert them to absolute offsets }
  65.                 rangeStart := pWE^.tsmAreaStart + pRange^.fStart;
  66.                 rangeEnd := pWE^.tsmAreaStart + pRange^.fEnd;
  67.                 hiliteStyle := pRange^.fHiliteStyle;
  68.  
  69. { take the absolute value of hiliteStyle }
  70.                 hiliteStyle := ABS(hiliteStyle);
  71.  
  72. { if hiliteStyle is kCaretPosition, set the selection range }
  73.                 if (hiliteStyle = kCaretPosition) then
  74.                     begin
  75.                         pWE^.selStart := rangeStart;
  76.                         pWE^.selEnd := rangeEnd;
  77.                     end
  78.                 else
  79.                     begin
  80.                         hiliteStyle := hiliteStyle - kRawText;
  81.  
  82. { otherwise set the WETextStyle flags of the specified range appropriately }
  83.                         if ((hiliteStyle >= 0) and (hiliteStyle <= 3)) then
  84.                             begin
  85.                                 ts.tsFlags := $10 + BSL(hiliteStyle, tsTSMSelected);
  86.                                 err := _WESetStyleRange(rangeStart, rangeEnd, weDoFlags, ts, hWE);
  87.                                 if (err <> noErr) then
  88.                                     goto 1;
  89.                             end;
  90.                     end;
  91.  
  92. { go to next text range element }
  93.                 rangeIndex := rangeIndex - 1;
  94.                 pRange := TextRangePtr(LongInt(pRange) + SizeOf(TextRange));
  95.             end;  { while }
  96.  
  97. { clear result code }
  98.         err := noErr;
  99.  
  100. 1:
  101. { unlock the range array }
  102.         IgnoreBoolean(_WESetHandleLock(hTray, saveTrayLock));
  103.  
  104. { return result code }
  105.         _WEHiliteRangeArray := err;
  106.  
  107.     end;  { _WEHiliteRangeArray }
  108.  
  109.     function _WEHandleUpdateActiveInputArea (var ae, reply: AppleEvent;
  110.                                     handlerRefCon: LongInt): OSErr;
  111.         label
  112.             1;
  113.         var
  114.             hWE: WEHandle;
  115.             pWE: WEPtr;
  116.             text: AEDesc;
  117.             hiliteTray: AEDesc;
  118.             pinRange: TextRange;
  119.             totalLength: LongInt;
  120.             fixLength: LongInt;
  121.             tsmOffset: LongInt;
  122.             returnedType: DescType;
  123.             actualSize: LongInt;
  124.             savePort: GrafPtr;
  125.             hAction: WEActionHandle;
  126.             saveAutoScroll: Boolean;
  127.             saveTextLock: Boolean;
  128.             saveWELock: Boolean;
  129.             err: OSErr;
  130.     begin
  131.         hWE := nil;
  132.  
  133. { initialize descriptors to null values }
  134.         text.descriptorType := typeNull;
  135.         text.dataHandle := nil;
  136.         hiliteTray.descriptorType := typeNull;
  137.         hiliteTray.dataHandle := nil;
  138.  
  139. { extract WE handle }
  140.         err := AEGetParamPtr(ae, keyAETSMDocumentRefCon, typeLongInteger, returnedType, @hWE, SizeOf(hWE), actualSize);
  141.         if (err <> noErr) then
  142.             goto 1;
  143.  
  144. { lock the WE handle }
  145.         saveWELock := _WESetHandleLock(hWE, true);
  146.         pWE := hWE^;
  147.  
  148. { call the pre-update callback, if present }
  149.         if (pWE^.tsmPreUpdate <> nil) then
  150.             CallPreUpdate(hWE, pWE^.tsmPreUpdate);
  151.  
  152. { hide the caret if it's showing }
  153.         if BTST(pWE^.flags, weFCaretVisible) then
  154.             _WEBlinkCaret(hWE);
  155.  
  156. { extract the text descriptor }
  157.         err := AEGetParamDesc(ae, keyAETheData, typeChar, text);
  158.         if (err <> noErr) then
  159.             goto 1;
  160.  
  161. { get total length of text in the active input area }
  162.         totalLength := %_GetHandleSize(text.dataHandle);
  163.  
  164. { extract the length of confirmed text in the active input area }
  165.         err := AEGetParamPtr(ae, keyAEFixLength, typeLongInteger, returnedType, @fixLength, SizeOf(fixLength), actualSize);
  166.         if (err <> noErr) then
  167.             goto 1;
  168.  
  169. { if fixLength = -1, all text is confirmed }
  170.         if (fixLength = -1) then
  171.             fixLength := totalLength;
  172.  
  173. { if there's currently no active input area, open one }
  174.         if (pWE^.tsmAreaStart = kInvalidOffset) then
  175.             begin
  176.                 pWE^.tsmAreaStart := pWE^.selStart;
  177.                 pWE^.tsmAreaEnd := pWE^.selEnd;
  178.  
  179. { are we tracking a typing sequence? }
  180.                 if (WEIsTyping(hWE) = false) then
  181.                     begin
  182.  
  183. { nope; so start a new one }
  184. { increment modification count }
  185.                         pWE^.modCount := pWE^.modCount + 1;
  186.  
  187. { if undo support is enabled, create a new action to keep track of the typing }
  188.                         if (BTST(pWE^.flags, weFUndoSupport)) then
  189.                             begin
  190.                                 WEClearUndo(hWE);
  191.                                 if (WENewAction(pWE^.selStart, pWE^.selEnd, 0, weAKTyping, 0, hWE, hAction) = noErr) then
  192.                                     if (WEPushAction(hAction) <> noErr) then
  193.                                         ;
  194.                             end;
  195.                     end;
  196.             end;
  197.  
  198.         tsmOffset := pWE^.tsmAreaStart;
  199.  
  200. { the new text replaces whatever is in the active input area }
  201.         err := _WEDeleteRange(tsmOffset, pWE^.tsmAreaEnd, hWE);
  202.         if (err <> noErr) then
  203.             goto 1;
  204.  
  205. { synchronize the null style, so font script matches the keyboard script }
  206.         _WESynchNullStyle(hWE);
  207.  
  208. { set the port font for good measure }
  209.         GetPort(savePort);
  210.         SetPort(pWE^.port);
  211.         TextFont(pWE^.nullStyle.runStyle.tsFont);
  212.         SetPort(savePort);
  213.  
  214. { temporarily lock the text }
  215.         saveTextLock := _WESetHandleLock(text.dataHandle, true);
  216.  
  217. { insert the text }
  218.         err := _WEInsertText(tsmOffset, text.dataHandle^, totalLength, hWE);
  219.         if (err <> noErr) then
  220.             goto 1;
  221.  
  222. { unlock the text }
  223.         IgnoreBoolean(_WESetHandleLock(text.dataHandle, saveTextLock));
  224.  
  225. { extract pin range }
  226.         err := AEGetParamPtr(ae, keyAEPinRange, typeTextRange, returnedType, @pinRange, SizeOf(pinRange), actualSize);
  227.         if (err = noErr) then
  228.             begin
  229.  
  230. { we want absolute offsets }
  231.                 pinRange.fStart := pinRange.fStart + tsmOffset;
  232.                 pinRange.fEnd := pinRange.fEnd + tsmOffset;
  233.             end
  234.         else
  235.             begin
  236.  
  237. { a missing pin range descriptor isn't an error; everything else is }
  238.                 if (err <> errAEDescNotFound) then
  239.                     goto 1;
  240.  
  241. { default pin range is active input area }
  242.                 pinRange.fStart := tsmOffset;
  243.                 pinRange.fEnd := pWE^.tsmAreaEnd;
  244.             end;
  245.  
  246. { extract the highlight range array }
  247.         err := AEGetParamDesc(ae, keyAEHiliteRange, typeTextRangeArray, hiliteTray);
  248.         if (err <> noErr) then
  249.             if (err <> errAEDescNotFound) then
  250.                 goto 1;
  251.  
  252.         if (hiliteTray.dataHandle <> nil) then
  253.             begin
  254.                 err := _WEHiliteRangeArray(TextRangeArrayHandle(hiliteTray.dataHandle), hWE);
  255.                 if (err <> noErr) then
  256.                     goto 1;
  257.             end
  258.         else
  259.             begin
  260.                 pWE^.selStart := tsmOffset + fixLength;
  261.                 pWE^.selEnd := pWE^.selStart;
  262.             end;
  263.  
  264. { temporarily disable auto-scroll, as we need to scroll manually according to pinRange }
  265.         saveAutoScroll := BTST(pWE^.flags, weFAutoScroll);
  266.         BCLR(pWE^.flags, weFAutoScroll);
  267.  
  268. { redraw the active input area }
  269.         err := _WERedraw(tsmOffset, tsmOffset + totalLength, hWE);
  270.         if (err <> noErr) then
  271.             goto 1;
  272.  
  273.         if (saveAutoScroll) then
  274.             begin
  275.  
  276. { re-enable auto-scroll }
  277.                 BSET(pWE^.flags, weFAutoScroll);
  278.  
  279. { scroll the pin range into view }
  280.                 if (_WEScrollIntoView(pinRange.fStart, hWE) = false) then
  281.                     if (pinRange.fStart <> pinRange.fEnd) then
  282.                         IgnoreBoolean(_WEScrollIntoView(pinRange.fEnd, hWE));
  283.             end;
  284.  
  285. { update the boundaries of the active input area }
  286. { if fixLength = totalLength, the inline input session is over: close the active input area }
  287.         if (fixLength = totalLength) then
  288.             begin
  289.                 pWE^.tsmAreaStart := kInvalidOffset;
  290.                 pWE^.tsmAreaEnd := kInvalidOffset;
  291.  
  292. { adjust undo buffer (if any) for the confirmed text }
  293.                 _WEAdjustUndoRange(fixLength, hWE);
  294.             end
  295.         else
  296.             begin
  297.  
  298. { otherwise, fixLength defines the boundaries of the active input area }
  299.                 pWE^.tsmAreaStart := tsmOffset + fixLength;
  300.                 pWE^.tsmAreaEnd := tsmOffset + totalLength;
  301.             end;
  302.  
  303. { call the post-update callback, if present }
  304.         if (pWE^.tsmPostUpdate <> nil) then
  305.             CallPostUpdate(hWE, fixLength, pWE^.tsmAreaStart, pWE^.tsmAreaEnd, pinRange.fStart, pinRange.fEnd, pWE^.tsmPostUpdate);
  306.  
  307. { clear result code }
  308.         err := noErr;
  309.  
  310. 1:
  311. { clean up }
  312.         IgnoreShort(AEDisposeDesc(text));
  313.         IgnoreShort(AEDisposeDesc(hiliteTray));
  314.  
  315. { unlock the WE record }
  316.         IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
  317.  
  318. { return result code }
  319.         _WEHandleUpdateActiveInputArea := err;
  320.  
  321.     end;  { _WEHandleUpdateActiveInputArea }
  322.  
  323.     function _WEHandlePositionToOffset (var ae, reply: AppleEvent;
  324.                                     handlerRefCon: LongInt): OSErr;
  325.         label
  326.             1;
  327.         var
  328.             hWE: WEHandle;
  329.             pWE: WEPtr;
  330.             position: Point;
  331.             thePoint: LongPoint;
  332.             regionClass: Integer;
  333.             offset: LongInt;
  334.             returnedType: DescType;
  335.             actualSize: LongInt;
  336.             savePort: GrafPtr;
  337.             edge: SignedByte;
  338.             saveWELock: Boolean;
  339.             err: OSErr;
  340.     begin
  341.         hWE := nil;
  342.  
  343. { extract WE handle }
  344.         err := AEGetParamPtr(ae, keyAETSMDocumentRefCon, typeLongInteger, returnedType, @hWE, SizeOf(hWE), actualSize);
  345.         if (err <> noErr) then
  346.             goto 1;
  347.  
  348. { lock the WE record }
  349.         saveWELock := _WESetHandleLock(hWE, true);
  350.         pWE := hWE^;
  351.  
  352. { extract position parameter }
  353.         err := AEGetParamPtr(ae, keyAECurrentPoint, typeQDPoint, returnedType, @position, SizeOf(position), actualSize);
  354.         if (err <> noErr) then
  355.             goto 1;
  356.  
  357. { convert position to local... }
  358.         GetPort(savePort);
  359.         SetPort(pWE^.port);
  360.         GlobalToLocal(position);
  361.         SetPort(savePort);
  362.  
  363. { ...and long coordinates }
  364.         WEPointToLongPoint(position, thePoint);
  365.  
  366. { find the byte offset and the edge value corresponding to the given position }
  367.         offset := WEGetOffset(thePoint, edge, hWE);
  368.  
  369. { add offset parameter to reply }
  370.         err := AEPutParamPtr(reply, keyAEOffset, typeLongInteger, @offset, SizeOf(offset));
  371.         if (err <> noErr) then
  372.             goto 1;
  373.  
  374. { add edge parameter to reply }
  375.         err := AEPutParamPtr(reply, keyAELeftSide, typeBoolean, @edge, SizeOf(edge));
  376.         if (err <> noErr) then
  377.             goto 1;
  378.  
  379. { determine the region class }
  380.         if (WELongPointInLongRect(thePoint, pWE^.viewRect)) then
  381.             if (_WEOffsetInRange(offset, edge, pWE^.tsmAreaStart, pWE^.tsmAreaEnd)) then
  382.                 regionClass := kTSMInsideOfActiveInputArea
  383.             else
  384.                 regionClass := kTSMInsideOfBody
  385.         else
  386.             regionClass := kTSMOutsideOfBody;
  387.  
  388. { add region class parameter to reply }
  389.         err := AEPutParamPtr(reply, keyAERegionClass, typeShortInteger, @regionClass, SizeOf(regionClass));
  390.         if (err <> noErr) then
  391.             goto 1;
  392.  
  393. { clear result code }
  394.         err := noErr;
  395.  
  396. 1:
  397. { unlock the WE record }
  398.         if (hWE <> nil) then
  399.             IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
  400.  
  401. { return result code }
  402.         _WEHandlePositionToOffset := err;
  403.  
  404.     end;  { _WEHandlePositionToOffset }
  405.  
  406.     function _WEHandleOffsetToPosition (var ae, reply: AppleEvent;
  407.                                     handlerRefCon: LongInt): OSErr;
  408.         label
  409.             1;
  410.         var
  411.             hWE: WEHandle;
  412.             pWE: WEPtr;
  413.             offset: LongInt;
  414.             thePoint: LongPoint;
  415.             position: Point;
  416.             lineHeight: Integer;
  417.             returnedType: DescType;
  418.             actualSize: LongInt;
  419.             savePort: GrafPtr;
  420.             saveWELock: Boolean;
  421.             err: OSErr;
  422.     begin
  423.         hWE := nil;
  424.  
  425. { extract WE handle }
  426.         err := AEGetParamPtr(ae, keyAETSMDocumentRefCon, typeLongInteger, returnedType, @hWE, SizeOf(hWE), actualSize);
  427.         if (err <> noErr) then
  428.             goto 1;
  429.  
  430. { lock the WE record }
  431.         saveWELock := _WESetHandleLock(hWE, true);
  432.         pWE := hWE^;
  433.  
  434. { if there's no active input area, return errOffsetInvalid }
  435.         if (pWE^.tsmAreaStart < 0) then
  436.             begin
  437.                 err := errOffsetInvalid;
  438.                 goto 1;
  439.             end;
  440.  
  441. { extract the offset parameter }
  442.         err := AEGetParamPtr(ae, keyAEOffset, typeLongInteger, returnedType, @offset, SizeOf(offset), actualSize);
  443.         if (err <> noErr) then
  444.             goto 1;
  445.  
  446. { offset is relative to the beginning of the active input area; we want an absolute offset }
  447.         offset := offset + pWE^.tsmAreaStart;
  448.  
  449. { make sure the offset is within the input area }
  450.         if (offset < pWE^.tsmAreaStart) or (offset >= pWE^.tsmAreaEnd) then
  451.             begin
  452.                 err := errOffsetInvalid;
  453.                 goto 1;
  454.             end;
  455.  
  456. { find the position corresponding to the given offset (in long coordinates) }
  457.         WEGetPoint(offset, thePoint, lineHeight, hWE);
  458.         thePoint.v := thePoint.v + lineHeight;
  459.  
  460. { make sure offset is within view rectangle }
  461.         if (not WELongPointInLongRect(thePoint, pWE^.viewRect)) then
  462.             begin
  463.                 err := errOffsetIsOutsideOfView;
  464.                 goto 1;
  465.             end;
  466.  
  467. { convert the point to short... }
  468.         WELongPointToPoint(thePoint, position);
  469.  
  470. { ...and global coordinates }
  471.         GetPort(savePort);
  472.         SetPort(pWE^.port);
  473.         LocalToGlobal(position);
  474.         SetPort(savePort);
  475.  
  476. { add keyAEPoint parameter to the reply Apple event }
  477.         err := AEPutParamPtr(reply, keyAEPoint, typeQDPoint, @position, SizeOf(position));
  478.         if (err <> noErr) then
  479.             goto 1;
  480.  
  481. { add keyAETextFont parameter to the reply Apple event }
  482.         err := AEPutParamPtr(reply, keyAETextFont, typeShortInteger, @pWE^.nullStyle.runStyle.tsFont, SizeOf(pWE^.nullStyle.runStyle.tsFont));
  483.         if (err <> noErr) then
  484.             goto 1;
  485.  
  486. { add keyAETextPointSize parameter to the reply Apple event }
  487.         err := AEPutParamPtr(reply, keyAETextPointSize, typeShortInteger, @pWE^.nullStyle.runStyle.tsSize, SizeOf(pWE^.nullStyle.runStyle.tsSize));
  488.         if (err <> noErr) then
  489.             goto 1;
  490.  
  491. { add keyAETextLineAscent parameter to the reply Apple event }
  492.         err := AEPutParamPtr(reply, keyAETextLineAscent, typeShortInteger, @pWE^.nullStyle.runAscent, SizeOf(pWE^.nullStyle.runAscent));
  493.         if (err <> noErr) then
  494.             goto 1;
  495.  
  496. { add keyAETextLineHeight parameter to the reply Apple event }
  497.         err := AEPutParamPtr(reply, keyAETextLineHeight, typeShortInteger, @pWE^.nullStyle.runHeight, SizeOf(pWE^.nullStyle.runHeight));
  498.         if (err <> noErr) then
  499.             goto 1;
  500.  
  501. { clear result code }
  502.         err := noErr;
  503.  
  504. 1:
  505. { unlock the WE record }
  506.         if (hWE <> nil) then
  507.             IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
  508.  
  509. { return result code }
  510.         _WEHandleOffsetToPosition := err;
  511.  
  512.     end;  { _WEHandleOffsetToPosition }
  513.  
  514. {$IFC WASTE_SEGMENT}
  515. {$S WASTE_INIT}
  516. {$ENDC}
  517.  
  518.     function WEInstallTSMHandlers: OSErr;
  519.         label
  520.             1;
  521.         var
  522.             err: OSErr;
  523.     begin
  524.  
  525. { install Apple Event handlers to be used by Text Service components }
  526.         err := AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea, @_WEHandleUpdateActiveInputArea, 0, false);
  527.         if (err <> noErr) then
  528.             goto 1;
  529.  
  530.         err := AEInstallEventHandler(kTextServiceClass, kPos2Offset, @_WEHandlePositionToOffset, 0, false);
  531.         if (err <> noErr) then
  532.             goto 1;
  533.  
  534.         err := AEInstallEventHandler(kTextServiceClass, kOffset2Pos, @_WEHandleOffsetToPosition, 0, false);
  535.         if (err <> noErr) then
  536.             goto 1;
  537.  
  538. { clear result code }
  539.         err := noErr;
  540.  
  541. 1:
  542. { return result code }
  543.         WEInstallTSMHandlers := err;
  544.  
  545.     end;  { WEInstallTSMHandlers }
  546.  
  547. end.